package com.zhangdi.dwperms.service.impl;

import com.zhangdi.dwperms.cache.CacheTokenService;
import com.zhangdi.dwperms.commons.Contents;
import com.zhangdi.dwperms.dao.AccountDao;
import com.zhangdi.dwperms.dao.OAuthDao;
import com.zhangdi.dwperms.dao.UserDao;
import com.zhangdi.dwperms.entity.OAuth;
import com.zhangdi.dwperms.exception.TokenExpiredException;
import com.zhangdi.dwperms.response.WxResponse;
import com.zhangdi.dwperms.enums.LoginType;
import com.zhangdi.dwperms.request.LoginRequest;
import com.zhangdi.dwcommons.request.RegisterRequest;
import com.zhangdi.dwcommons.response.Response;
import com.zhangdi.dwcommons.response.ResponseUtil;
import com.zhangdi.dwperms.service.AccountService;
import com.zhangdi.dwperms.commons.security.Security;
import com.zhangdi.dwperms.entity.Account;
import com.zhangdi.dwperms.entity.User;
import com.zhangdi.dwperms.token.AuthToken;
import com.zhangdi.dwperms.token.CacheToken;
import com.zhangdi.dwperms.token.MSToken;
import com.zhangdi.dwperms.token.TokenFactory;
import com.zhangdi.dwperms.token.TokenUtils;
import com.zhangdi.dwtools.text.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Service
public class AccountServiceImpl extends BaseSubject implements AccountService {
    @Resource
    AccountDao accountDao;
    @Resource
    UserDao userDao;
    @Resource
    OAuthDao oAuthDao;

    @Resource
    TokenUtils tokenUtils;

    @Resource
    CacheTokenService cacheTokenService;

    @Transactional
    @Override
    public Response register(RegisterRequest params) {
        Account account = accountDao.getOne("username", params.getUsername());
        if (account != null) {
            return ResponseUtil.error("该用户已存在");
        }

        Security security = new Security();

        account = new Account();
        account.setPassword(security.encrypt(params.getPassword()));
        account.setSalt(security.getSalt());
        account.setUsername(params.getUsername());
        account = accountDao.save(account);
        if (account == null) {
            return ResponseUtil.error("初始化账号时出错");
        }

        User user = new User();
        user.addRole(2L);
        user.setAccount(account);
        user = userDao.save(user);
        if (user == null) {
            return ResponseUtil.error("初始化用户时出错");
        }

        return ResponseUtil.success();
    }

    //TODO 抽象获取token
    @Transactional
    @Override
    public Response login(LoginRequest params, HttpServletResponse response) {
        AuthToken msToken = null;
        try {
            if (params.getType() == LoginType.account) {
                msToken = TokenFactory.build(LoginType.account, params.getUsername(), params.getPassword());
                doLogin(msToken);
            } else if (params.getType() == LoginType.wx) {
                Map<String, String> param = new HashMap<>();
                param.put("appid", "wx9ae2b054928305c1");
                param.put("secret", "ad8301ab44fedd579c3ece841f0bc5fc");
                param.put("js_code", params.getCode());
                param.put("grant_type", "authorization_code");
//                WxResponse wxResponse = RestTempleUtil.restTemplate().getForObject(
//                        WebHelper.createUrl("https://api.weixin.qq.com/sns/jscode2session", param),
//                        WxResponse.class);
                WxResponse wxResponse = new WxResponse();
                wxResponse.setOpenid(params.getCode());

                if (wxResponse == null) {
                    return ResponseUtil.error("授权失败");
                }
                OAuth oAuth = oAuthDao.getOne("uid", wxResponse.getOpenid());
                if (null == oAuth) {
                    //注册
                    System.out.println("未查询到openid，证明没有用户，注册一个");
                    String username = StringUtils.randomStr(6);
                    Account account = accountDao.getOne("username", username);
                    if (null != account) {
                        return ResponseUtil.error("授权失败，账号重复");
                    }

                    account = new Account();
                    account.setUsername(username);
                    account.setPassword(StringUtils.randomStr(8));
                    User user = new User();
                    user.setAccount(account);
                    account.setUser(user);
                    account = accountDao.save(account);

                    oAuth = new OAuth();
                    oAuth.setTokenType(params.getType().name());
                    oAuth.setUser(account.getUser());
                    oAuth.setUid(wxResponse.getOpenid());

                    oAuth = oAuthDao.save(oAuth);
                }
                String username = oAuth.getUser().getAccount().getUsername();
                msToken = TokenFactory.build(LoginType.wx, username, tokenUtils.getAccessToken(username));
                doLogin(msToken);
            } else if (params.getType() == LoginType.phone) {
                //TODO 验证码登录
                //1、从缓存中找验证码
                //2、没有找到返回失败
                //3、找到验证码，去库里查询手机号绑定的id，生成token给客户端
            }

            CacheToken cacheToken = new CacheToken(tokenUtils.encrypt(msToken), TokenUtils.getRefreshTimestamp(msToken));
            cacheTokenService.save(msToken.cacheKey(), cacheToken);
            response.setHeader(Contents.HEAD_KEY_TOKEN, cacheToken.getAccess_token());

            return ResponseUtil.success();
        } catch (UnknownAccountException e) {
            return ResponseUtil.error("账户不存在");
        } catch (IncorrectCredentialsException | LockedAccountException e) {
            return ResponseUtil.error("用户名或密码错误");
        } catch (AuthenticationException e) {
            return ResponseUtil.error("认证失败");
        } catch (TokenExpiredException e) {
            return ResponseUtil.error("登录状态过期");
        }
    }

    @Override
    public void logout(HttpServletRequest request) {
        String token = request.getHeader(Contents.HEAD_KEY_TOKEN);
        if (StringUtils.isBlank(token)) {
            return;
        }
        MSToken msToken = tokenUtils.decrypt(token);
        boolean result = cacheTokenService.remove(msToken.cacheKey());
        getSubject().logout();
    }
}
